<?php

	namespace Aspic\Preset;
	
	use Aspic as A;
	
	/**
	 * Implementation for CollectionInterface with basic features (implementing \Iterator)
	 */
	trait BasicCollectionTrait {
		
		/**
		 * @var array Collection items
		 */
		protected $items;
		
		protected $iteratorPosition;

		public function __construct() {
			$this->items = array();
			$this->iteratorPosition = 0;
		}
		
		public function addItem($item) {
			$this->offsetSet(count($this->items), $item);
		}
		
		/**
		 * This method is called before adding the item to check if it could be added
		 * Some test like "$item instanceof SomeClass" may be done here
		 * @param mixed $item An item that was asked to be added
		 */
		abstract protected function isAddableItem($item);

		public function removeAtIndex($index) {
			$this->items = A\UArray::removeFromIndex($this->items, $index);
		}

		public function remove($item) {
			$this->items = A\UArray::removeFromValue($this->items, $item, false);
		}
		
		##### INTERFACES IMPLEMENTATION #####
		
		public function toArray() {
			return $this->items;
		}
		
		public function rewind() {
			$this->iteratorPosition = 0;
		}

		public function current() {
			return $this->offsetGet[$this->position];
		}

		public function key() {
			return $this->iteratorPosition;
		}

		public function next() {
			++$this->iteratorPosition;
		}

		public function valid() {
			return $this->offsetExists($this->iteratorPosition);
		}

		public function offsetExists($offset) {
			return isset($this->items[$offset]);
		}

		public function offsetGet($offset) {
			return $this->items[$offset];
		}

		public function offsetSet($offset, $value) {
			if (!$this->isAddableItem($item)) {
				throw new \InvalidArgumentException(
					'Item given to the collection class "'.get_called_class().'" does not match pre-requisites (see "isAddable" method)'
				);
			}
			elseif(!is_numeric($offset)) {
				throw new A\Exception('Offset of a collection must be numeric, "'.$offset.'" given.');
			}
			
			$this->items[$offset] = $item;
		}

		public function offsetUnset($offset) {
			unset($this->items[$offset]);
		}
		
		public function count() {
			return count($this->items);
		}
	}
